﻿using Autofac;
using Autofac.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutofacDemo
{
    class Program
    {
        private static IContainer Container { get; set; }

        static void Main(string[] args)
        {

            var builder = new ContainerBuilder();
            //1
            builder.RegisterType<ConsoleLogger>().As<ILogger>();


            //2 Register expressions that execute to create objects...
            builder.Register(c => new ConfigReader("mysection")).As<IConfigReader>();


            //3 Register instances of objects you create...
            var output = new StringWriter();
            builder.RegisterInstance(output).As<TextWriter>();

            //ExternallyOwned  自己来控制生命周期而不是让Autofac来帮你调用 Dispose 释放你的对象
            builder.RegisterInstance(output).As<TextWriter>().ExternallyOwned();

            //反射组件
            //通过类型注册
            builder.RegisterType<ConsoleLogger>();
            builder.RegisterType(typeof(ConfigReader));


            //4 Autofac 自动为你的类从容器中寻找匹配拥有最多参数的构造方法
            builder.RegisterType<MyComponent>();
            //指定构造参数
            //builder.RegisterType<MyComponent>().UsingConstructor(typeof(ILogger), typeof(IConfigReader));

            //5.复杂参数
            //builder.Register(c => new UserSession(DateTime.Now.AddMinutes(25)));


            //6.通过参数值选择具体的实现
            builder.Register<CreditCard>(
              (c, p) =>
              {
                  var accountId = p.Named<string>("accountId");
                  if (accountId.StartsWith("9"))
                  {
                      return new GoldCard(accountId);
                  }
                  else
                  {
                      return new StandardCard(accountId);
                  }
              });


            //7.开放泛型组件
            builder.RegisterGeneric(typeof(NHibernateRepository<>))
       .As(typeof(IRepository<>))
       .InstancePerLifetimeScope();


            //8.如果你既想组件暴露一系列特定的服务, 又想让它暴露默认的服务, 可以使用 AsSelf 方法
            // builder.RegisterType<CallLogger>()
            //.AsSelf()
            //.As<ILogger>()
            //.As<ICallInterceptor>();

            //9.默认注册
            builder.RegisterType<ConsoleLogger>().As<ILogger>();
            //builder.RegisterType<FileLogger>().As<ILogger>();//Autofac将使用最后注册的组件作为服务的提供方
            //builder.RegisterType<FileLogger>().As<ILogger>().PreserveExistingDefaults();//这样就不覆盖了

            //10. 有条件的注册 OnlyIf()  IfNotRegistered()

            //11.注册时传参
            ////1) lambda表达式组件
            //builder.Register(c => new ConfigReader("sectionName")).As<IConfigReader>();
            ////2)反射组件注册时传参
            //// Using a NAMED parameter:
            //builder.RegisterType<ConfigReader>()
            //       .As<IConfigReader>()
            //       .WithParameter("configSectionName", "sectionName");

            //// Using a TYPED parameter:
            //builder.RegisterType<ConfigReader>()
            //       .As<IConfigReader>()
            //       .WithParameter(new TypedParameter(typeof(string), "sectionName"));

            //// Using a RESOLVED parameter:
            //builder.RegisterType<ConfigReader>()
            //       .As<IConfigReader>()
            //       .WithParameter(
            //         new ResolvedParameter(
            //           (pi, ctx) => pi.ParameterType == typeof(string) && pi.Name == "configSectionName",
            //           (pi, ctx) => "sectionName"));
            ////3) lambda表达式在服务解析时 传入具体的参数值
            //// Use TWO parameters to the registration delegate:
            //// c = The current IComponentContext to dynamically resolve dependencies
            //// p = An IEnumerable<Parameter> with the incoming parameter set
            //builder.Register((c, p) =>
            //                 new ConfigReader(p.Named<string>("configSectionName")))
            //       .As<IConfigReader>();


            //12.属性注入
            //builder.Register(c => new A { B = c.Resolve<B>() });
            builder.RegisterType<PropertiesInject>().WithProperty("PropertyName", "abc");



            Container = builder.Build();

            // The WriteDate method is where we'll make use
            // of our dependency injection. We'll define that
            // in a bit.
            WriteDate();

            Console.ReadLine();
        }

        public static void WriteDate()
        {
            // Create the scope, resolve your IDateWriter,
            // use it, then dispose of the scope.
            using (var scope = Container.BeginLifetimeScope())
            {
                //1
                var logger = scope.Resolve<ILogger>();
                logger.Info();
                //2
                var configReader = scope.Resolve<IConfigReader>();
                configReader.Read();
                //3
                var writer = scope.Resolve<TextWriter>();

                //4 自动为你的类从容器中寻找匹配拥有最多参数的构造方法
                var component = scope.Resolve<MyComponent>();

                //6 通过参数值选择具体的实现
                var card = scope.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));

                //7
                var tasks = scope.Resolve<IRepository<Task>>();

                //12 
                var propertiesInject = scope.Resolve<PropertiesInject>();
            }
        }
    }
}
